#include <iostream>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void Usage(std::string proc)
{
    //提示用户使用错误
    std::cout << "Usage:\n\t" << proc << "server_ip server_port" << std::endl;
}

//./udp_client server_ip server_port
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        return 0;
    }

    // 1、创建套接字
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        std::cerr << "socket create erro:" << errno << std::endl;
        return 1;
    }

    //客户端必须也要有ip和port，但是客户端不需要显示bind
    //因为一旦显示bind就必须明确，client要和哪一个端口号关联
    // server的端口要明确且不变，这样才能方便给client提供服务
    //但是client获取服务只要有端口可用就行，没必要指明哪一个端口
    //一般由OS自动给你bind()，在client发送数据时，OS会自动给你bind
    //采用的是随机bind端口的方式

    // 2、使用服务
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    //端口号输入时是字符串类型，需要转成int类型，所以使用atoi
    //由于是主机序列，要通信的话需要主机转网络用htons
    server.sin_port = htons(atoi(argv[2]));
    server.sin_addr.s_addr = inet_addr(argv[1]);

    while (1)
    {
        //输入信息
        std::string message;
        std::cout << "输入#";
        std::cin >> message;

        //发送信息
        //用于message是C++string类型，需要转换成C语言的字符串类型，用c_str()
        sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server));

        //其实可以不用创建tmp，可以直接使用server
        //只是避免有其他主机也给client发信息，所以创建一个tmp
        struct sockaddr_in tmp;
        socklen_t len = sizeof(tmp);
        char buffer[1024];

        //读取信息
        recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&tmp, &len);
        std::cout << "server echo#" << buffer << std::endl;
    }

    return 0;
}